﻿using System;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.ComponentModel;

//c:\Program Files\Microsoft SDKs\Windows\v6.0A\Include\WinUser.h

namespace PickGold.Api
{
	/// <summary>
	/// Api 通用类
	/// </summary>
	public static class Common
	{
		internal const string DLL_URLMON = "urlmon.dll";
		internal const string DLL_GDI32 = "gdi32.dll";
		internal const string DLL_GDIPLUS = "gdiplus.dll";
		internal const string DLL_SETUPAPI = "setupapi.dll";
		internal const string DLL_HID = "hid.dll";
		internal const string DLL_MPR = "mpr.dll";
		/// <summary>
		/// kernel32.dll
		/// </summary>
		internal const string DLL_KERNEL32 = "kernel32.dll";
		internal const string DLL_USER32 = "user32.dll";
		internal const string DLL_MSVFW32 = "MSVFW32.dll";
		internal const string DLL_OLE32 = "ole32.dll";
		internal const string DLL_SHELL32 = "shell32.dll";
		internal const string DLL_WINMM = "winmm.dll";
		internal const string DLL_WININET = "wininet.dll";
		internal const string DLL_RASAPI32 = "rasapi32.dll";
		internal const string DLL_WINSPOOL = "winspool.drv";

		/// <summary/>
		public const int METHOD_BUFFERED = 0;

		/// <summary>
		/// Monitor Power
		/// </summary>
		/// <returns>return SendMessage(Handle, 0x0112, 0xF170, 2)</returns>
		public static IntPtr MonitorPower()
		{
			return Common.MonitorPower(false);
		}
		/// <summary>
		/// Monitor Power
		/// </summary>
		/// <param name="on">on ? -1 : 2</param>
		/// <returns>return SendMessage(Handle, 0x0112, 0xF170, on ? -1 : 2)</returns>
		public static IntPtr MonitorPower(bool on)
		{
			return User32.SendMessage(System.Diagnostics.Process.GetCurrentProcess().Handle, WM.SYSCOMMAND, SC.MONITORPOWER, on ? -1 : 2);
		}

		/// <summary>
		/// GetApiEntryPoint DllImportAttribute::EntryPoint
		/// </summary>
		/// <param name="method">MethodBase</param>
		/// <returns>DllImportAttribute::EntryPoint Or MethodBase::Name</returns>
		public static string GetApiEntryPoint(this MethodBase method)
		{
			var os = method.GetCustomAttributes(typeof(DllImportAttribute), true);
			if (os == null || os.Length == 0)
				return null;

			if (os.Length == 1)
			{
				var dia = os[0] as DllImportAttribute;
				if (dia == null)
					return null;

				if (string.IsNullOrEmpty(dia.EntryPoint))
					return method.Name;

				return dia.EntryPoint;
			}

			foreach (var o in os)
			{
				if (o == null)
					continue;

				var dia = o as DllImportAttribute;
				if (dia != null && !string.IsNullOrEmpty(dia.EntryPoint))
					return dia.EntryPoint;
			}

			return method.Name;
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="sessionMode"></param>
		/// <param name="session"></param>
		/// <param name="reserved"></param>
		//[DllImport(DLL_URLMON)]
		//public static extern void CoInternetGetSession(int sessionMode, out IInternetSession session, int reserved);
	}

	#region public static class WinInet

	/// <summary>
	/// wininet.dll
	/// </summary>
	public static class WinInet
	{
		/// <summary>
		/// 要删除的类型
		/// </summary>
		public enum DEL_CACHE_TYPE
		{
			/// <summary>
			/// 表示internet临时文件
			/// </summary>
			File,
			/// <summary>
			/// 表示Cookie
			/// </summary>
			Cookie
		}

		/// <summary>
		/// wininet.dll
		/// </summary>
		public const string DLL = Common.DLL_WININET;

		public const int INTERNET_DIALSTATE_DISCONNECTED = 1;
		public const int INTERNET_AUTODIAL_FORCE_ONLINE = 1;
		public const int INTERNET_AUTODIAL_FORCE_UNATTENDED = 2;
		public const int INTERNET_DIAL_UNATTENDED = 0x8000;
		/// <summary>
		/// 本系统使用调制解调器与因特网相连
		/// </summary>
		public const int INTERNET_CONNECTION_MODEM = 0x01;
		/// <summary>
		/// 本系统通过LAN与因特网相连
		/// </summary>
		public const int INTERNET_CONNECTION_LAN = 0x02;
		/// <summary>
		/// 本系统使用proxy代理服务器与因特网相连
		/// </summary>
		public const int INTERNET_CONNECTION_PROXY = 0x04;
		public const int INTERNET_CONNECTION_MODEM_BUSY = 0x08;
		public const int INTERNET_RAS_INSTALLED = 0x10;
		public const int INTERNET_CONNECTION_OFFLINE = 0x20;
		public const int INTERNET_CONNECTION_CONFIGURED = 0x40;

		public const int AUTODIAL_MODE_NEVER = 1;
		public const int AUTODIAL_MODE_ALWAYS = 2;
		public const int AUTODIAL_MODE_NO_NETWORK_PRESENT = 4;

		/// <summary/>
		[DllImport(DLL, CharSet = CharSet.Auto, SetLastError = true)]
		public static extern bool InternetSetCookie(string lpszUrlName, string lbszCookieName, string lpszCookieData);

		/// <summary/>
		[DllImport(DLL, CharSet = CharSet.Auto, SetLastError = true)]
		public static extern int InternetSetCookieEx(string lpszURL, string lpszCookieName, string lpszCookieData, int dwFlags, IntPtr dwReserved);

		/// <summary/>
		[DllImport(DLL, CharSet = CharSet.Auto, SetLastError = true)]
		public static extern bool InternetGetCookieEx(string pchURL, string pchCookieName, StringBuilder pchCookieData, ref int pcchCookieData, int dwFlags, object lpReserved);  

		/// <summary>
		/// InternetGetConnectedState
		/// </summary>
		/// <param name="lpdwFlags">?</param>
		/// <param name="dwReserved">0</param>
		/// <returns></returns>
		[DllImport(DLL)]
		public static extern int InternetGetConnectedState([In][Out][MarshalAs(UnmanagedType.U4)] ref int lpdwFlags, int dwReserved);

		/// <summary/>
		[DllImport(DLL)]//, CharSet = CharSet.Auto, EntryPoint = "InternetGetConnectedStateExW"
		public static extern int InternetGetConnectedStateEx([Out]out int lpdwFlags, [Out]out string lpszConnectionName, int dwNameLen, int dwReserved);// [MarshalAs(UnmanagedType.LPTStr)]

		/// <summary/>
		[DllImport(DLL)]//, CharSet = CharSet.Auto, EntryPoint = "InternetGetConnectedStateExW"
		public static extern int InternetGetConnectedStateEx([Out]out int lpdwFlags, StringBuilder lpszConnectionName, int dwNameLen, int dwReserved);// [MarshalAs(UnmanagedType.LPTStr)]

		/// <summary>
		/// InternetAutoDial
		/// </summary>
		/// <param name="dwFlags">值设为2，该函数无需用户干预就可自动拨号。但使用该函数有一个前提：始终拨打默认连接</param>
		/// <param name="hwndParent">?</param>
		/// <returns>?</returns>
		[DllImport(DLL)]
		public static extern int InternetAutoDial([MarshalAs(UnmanagedType.U4)] int dwFlags, IntPtr hwndParent);

		/// <summary>
		/// InternetAutodialHangup
		/// </summary>
		/// <param name="dwReserved">?</param>
		/// <returns>?</returns>
		[DllImport(DLL)]
		public static extern int InternetAutodialHangup(int dwReserved);

		/// <summary>
		/// 
		/// </summary>
		/// <param name="hwnd"></param>
		/// <param name="lpszConnectoid"></param>
		/// <param name="dwFlags">INTERNET_AUTO_DIAL_UNATTENDED = 2</param>
		/// <param name="lpdwConnection"></param>
		/// <param name="dwReserved"></param>
		/// <returns></returns>
		[DllImport(DLL, CharSet = CharSet.Auto)]
		public extern static int InternetDial(IntPtr hwnd, [In]string lpszConnectoid, uint dwFlags, [Out]out int lpdwConnection, uint dwReserved);

		/// <summary/>
		[DllImport(DLL, CharSet = CharSet.Auto)]
		public extern static int InternetHangUp(int dwConnection, int dwReserved);

		/// <summary>
		/// 
		/// </summary>
		/// <param name="type"></param>
		/// <returns></returns>
		[DllImport(DLL, CharSet = CharSet.Auto)]
		public static extern int DeleteUrlCacheEntry(DEL_CACHE_TYPE type);
	}

	#endregion

	#region public static class RasApi32

	public static class RasApi32
	{
		public struct RASCONN
		{
			public int SizeOfThis()
			{
				dwSize = Marshal.SizeOf(this);
				return dwSize;
			}

			public int dwSize;
			public IntPtr hrasconn;
			[MarshalAs(UnmanagedType.ByValTStr, SizeConst = RAS_MaxEntryName + 1)]
			public string szEntryName;
			[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 17)]
			public string szDeviceType;
			[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 129)]
			public string szDeviceName;
		}

		[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
		public struct RasStats
		{
			public int dwSize;
			public int dwBytesXmited;
			public int dwBytesRcved;
			public int dwFramesXmited;
			public int dwFramesRcved;
			public int dwCrcErr;
			public int dwTimeoutErr;
			public int dwAlignmentErr;
			public int dwHardwareOverrunErr;
			public int dwFramingErr;
			public int dwBufferOverrunErr;
			public int dwCompressionRatioIn;
			public int dwCompressionRatioOut;
			public int dwBps;
			public int dwConnectionDuration;
		}

		[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
		public struct RasEntryName
		{
			public int dwSize;
			//[MarshalAs(UnmanagedType.ByValTStr,SizeConst=(int)RasFieldSizeConstants.RAS_MaxEntryName + 1)]
			public string szEntryName;
			//#if WINVER5
			// public int dwFlags;
			// [MarshalAs(UnmanagedType.ByValTStr,SizeConst=260+1)]
			// public string szPhonebookPath;
			//#endif
		}

		[StructLayout(LayoutKind.Sequential, Pack = 4, CharSet = CharSet.Auto)]
		public struct RASDIALPARAMS
		{
			public int dwSize;
			[MarshalAs(UnmanagedType.ByValTStr, SizeConst = RAS_MaxEntryName + 1)]
			public string szEntryName;
			[MarshalAs(UnmanagedType.ByValTStr, SizeConst = RAS_MaxPhoneNumber + 1)]
			public string szPhoneNumber;
			[MarshalAs(UnmanagedType.ByValTStr, SizeConst = RAS_MaxCallbackNumber + 1)]
			public string szCallbackNumber;
			[MarshalAs(UnmanagedType.ByValTStr, SizeConst = UNLEN + 1)]
			public string szUserName;
			[MarshalAs(UnmanagedType.ByValTStr, SizeConst = PWLEN + 1)]
			public string szPassword;
			[MarshalAs(UnmanagedType.ByValTStr, SizeConst = DNLEN + 1)]
			public string szDomain;
			public int dwSubEntry;
			public int dwCallbackId;
		}

		private const int RAS_MaxDeviceType = 16;
		private const int RAS95_MaxDeviceName = 128;
		private const int RAS95_MaxEntryName = 256;
		private const int RAS_MaxEntryName = 256;
		private const int RAS_MaxPhoneNumber = 16;
		private const int RAS_MaxCallbackNumber = 128;
		private const int UNLEN = 256;
		private const int PWLEN = 256;
		private const int DNLEN = 256;

		public const string DLL = Common.DLL_RASAPI32;

		/// <summary>
		/// 
		/// </summary>
		/// <param name="lprasconn">buffer to receive connections data</param>
		/// <param name="lpcb">size in bytes of buffer</param>
		/// <param name="lpcConnections">number of connections written to buffer</param>
		/// <returns></returns>
		[DllImport(DLL, EntryPoint = "RasEnumConnectionsA", SetLastError = true)]
		public static extern int RasEnumConnections(ref RASCONN lprasconn, ref int lpcb, ref int lpcConnections);

		/// <summary>
		/// 
		/// </summary>
		/// <param name="hRasConn">handle to the connection</param>
		/// <param name="lpStatistics">buffer to receive statistics</param>
		/// <returns></returns>
		[DllImport(DLL, CharSet = CharSet.Auto)]
		internal static extern uint RasGetConnectionStatistics(IntPtr hRasConn, [In, Out]RasStats lpStatistics);

		//[DllImport("Rasapi32.dll", CharSet = CharSet.Auto)]
		//public static extern int RasDial(int lpRasDialExtensions, string lpszPhonebook, ref   RASDIALPARAMS lprasdialparams, int dwNotifierType, Callback lpvNotifier, ref   int lphRasConn);

		/// <summary>
		/// 
		/// </summary>
		/// <param name="hrasconn">handle to the RAS connection to hang up</param>
		/// <returns></returns>
		[DllImport(DLL, CharSet = CharSet.Auto)]
		public extern static uint RasHangUp(IntPtr hrasconn);

		/// <summary>
		/// 
		/// </summary>
		/// <param name="reserved">reserved, must be NULL</param>
		/// <param name="lpszPhonebook">pointer to full path and file name of phone-book file</param>
		/// <param name="lprasentryname">buffer to receive phone-book entries</param>
		/// <param name="lpcb">size in bytes of buffer</param>
		/// <param name="lpcEntries">number of entries written to buffer</param>
		/// <returns></returns>
		[DllImport(DLL, CharSet = CharSet.Auto)]
		public extern static uint RasEnumEntries(string reserved, string lpszPhonebook, [In, Out]RasEntryName[] lprasentryname, ref int lpcb, out int lpcEntries);
	}

	#endregion

	/// <summary>
	/// 网络映射
	/// </summary>
	public static class Mpr
	{
		public const string DLL = Common.DLL_MPR;

		/// <summary/>
		[DllImport(DLL)]
		public static extern int WNetAddConnection2A(NET_RESOURCE[] lpNetResource, string lpPassword, string lpUserName, int dwFlags);

		/// <summary/>
		[DllImport(DLL)]
		public static extern int WNetCancelConnection2A(string sharename, int dwFlags, int fForce);

		/// <summary>
		/// 映射网络驱动器
		/// </summary>
		/// <param name="driveLetter">本地盘符，可为空，如果为空则从Z开始自动选择一个未使用的有效盘符；like x:</param>
		/// <param name="sharePath">远程共享路径；like \\192.168.0.2\test</param>
		/// <param name="user">用户名</param>
		/// <param name="password">密码</param>
		/// <returns>本地盘符，如果盘符已被占用，则返回空。</returns>
		public static string Connect(string driveLetter, string sharePath, string user, string password)
		{
			var ds = Directory.GetLogicalDrives();
			if (string.IsNullOrEmpty(driveLetter))
			{
				for (var c = AsciiCode.Z; c >= AsciiCode.A; c--)
				{
					driveLetter = new string(new char[] { (char)c, Path.VolumeSeparatorChar });
					if (!ds.Contains(driveLetter, StringComparer.OrdinalIgnoreCase))
						break;
				}
			}
			else
			{
				if (driveLetter.Length == 1)
					driveLetter += Path.VolumeSeparatorChar;
				if (ds.Contains(driveLetter))
					return null;
			}
			if (driveLetter[0] == AsciiChar.A || driveLetter[0] == AsciiChar.B)
				return null;

			var net = new NET_RESOURCE[1];
			net[0].dwScope = RESOURCE_SCOPE.GLOBALNET;
			net[0].dwType = RESOURCE_TYPE.DISK;
			net[0].dwDisplayType = RESOURCE_DISPLAY_TYPE.SHARE;
			net[0].dwUsage = RESOURCE_USAGE.CONNECTABLE;
			net[0].lpLocalName = driveLetter;
			net[0].lpRemoteName = sharePath;
			Disconnect(driveLetter);
			var error = WNetAddConnection2A(net, password, user, 1);
			if (error != ERROR.SUCCESS)
				throw error.GetException();

			return driveLetter;
		}

		/// <summary/>
		public static int Disconnect(string driveLetter)
		{
			return WNetCancelConnection2A(driveLetter, 1, 1);
		}
	}

	#region WINDOWPLACEMENT

	/// <summary>
	/// 这个结构用于GetWindowPlacement和SetWindowPlacement函数以获取或设置窗口的状态及位置信息
	/// </summary>
	[ComVisible(true)]
	[StructLayout(LayoutKind.Sequential)]
	public struct WINDOWPLACEMENT
	{
		/// <summary>
		/// 表明可以指定最小化窗口的x和y坐标。如果是在ptMinPosition成员中设置坐标，则必须指定这个标志。 
		/// The ptMinPosition specifies the x,y location of the window when minimized.
		/// </summary>
		public static int WPF_SETMINPOSITION = 0x0001;
		/// <summary>
		/// 表明复原后的窗口将会被最大化，而不管它在最小化之前是否是最大化的。这个设置仅在下一次复原窗口时有效。它不改变缺省的复原操作。这个标志仅当showCmd成员中指定了SW_SHOWMINIMIZED时才有效。 
		/// The SW_SHOWMINIMIZED constant must be specified in the showCmd parameter. Indicates that the window should be maximized the next time it is restored.
		/// </summary>
		public static int WPF_RESTORETOMAXIMIZED = 0x0002;
		public static int WPF_ASYNCWINDOWPLACEMENT = 0x0004;

		private static WINDOWPLACEMENT _Empty;

		public static WINDOWPLACEMENT Empty
		{
			get
			{
				if (WINDOWPLACEMENT._Empty.Length != 44)
					WINDOWPLACEMENT._Empty.Length = 44;
				return WINDOWPLACEMENT._Empty;
			}
		}

		public static WINDOWPLACEMENT Create()
		{
			WINDOWPLACEMENT v = new WINDOWPLACEMENT();
			v.Length = 44;
			return v;
		}

		/// <summary>
		/// 这个结构的长度（size），必须是44
		/// </summary>
		public int Length;
		/// <summary>
		/// 指定了控制最小化窗口的位置的标志以及复原窗口的方法。
		/// WPF_SETMINPOSITION
		/// WPF_RESTORETOMAXIMIZED
		/// 两个常数之一或都是
		/// </summary>
		public int flags;
		/// <summary>
		/// 指定了窗口的当前显示状态。这个成员可以是 SW 值之一
		/// Visibility flags
		/// </summary>
		public int showCmd;
		/// <summary>
		/// 指定了窗口被最小化时左上角的位置。
		/// The x,y location of the window when minimized.
		/// </summary>
		public POINT ptMinPosition;
		/// <summary>
		/// 指定了窗口被最大化时左上角的位置。
		/// The x,y location of the window location when maximized.
		/// </summary>
		public POINT ptMaxPosition;
		/// <summary>
		/// 指定了窗口处于正常状态（复原）时的坐标。
		/// The position and size of the window when it is restored (normal condition).
		/// </summary>
		public RECT rcNormalPosition;
	}

	#endregion

	#region RANGE

	[ComVisible(true)]
	[StructLayout(LayoutKind.Sequential)]
	public struct RANGE
	{
		private readonly static RANGE _Empty;

		public static RANGE Empty
		{
			get
			{
				return RANGE._Empty;
			}
		}

		public int From;
		public int To;

		public int Start
		{
			set
			{
				this.From = value;
			}
			get
			{
				return this.From;
			}
		}

		public int End
		{
			set
			{
				this.To = value;
			}
			get
			{
				return this.To;
			}
		}
	}

	[ComVisible(true)]
	[StructLayout(LayoutKind.Sequential)]
	public struct RANGE64
	{
		private readonly static RANGE64 _Empty;

		public static RANGE64 Empty
		{
			get
			{
				return RANGE64._Empty;
			}
		}

		public long From;
		public long To;

		public long Start
		{
			set
			{
				this.From = value;
			}
			get
			{
				return this.From;
			}
		}

		public long End
		{
			set
			{
				this.To = value;
			}
			get
			{
				return this.To;
			}
		}
	}

	#endregion

	#region POINT

	[ComVisible(true)]
	[StructLayout(LayoutKind.Sequential)]
	public struct POINT
	{
		private readonly static POINT _Empty;

		public static POINT Empty
		{
			get
			{
				return POINT._Empty;
			}
		}

		public int X;
		public int Y;
	}

	#endregion

	#region SIZE

	/// <summary>
	/// 
	/// </summary>
	[ComVisible(true)]
	[StructLayout(LayoutKind.Sequential)]
	public struct SIZE
	{
		private readonly static SIZE _Empty;

		public static SIZE Empty
		{
			get
			{
				return SIZE._Empty;
			}
		}

		public int Width;
		public int Height;
	}

	#endregion

	#region RECT

	/// <summary>
	/// 
	/// </summary>
	[ComVisible(true)]
	[StructLayout(LayoutKind.Sequential)]
	public struct RECT
	{
		private readonly static RECT _Empty;

		public static RECT Empty
		{
			get
			{
				return RECT._Empty;
			}
		}

		public int Left;
		public int Top;
		public int Right;
		public int Bottom;

		public POINT Point
		{
			get
			{
				var p = new POINT();
				p.X = this.Left;
				p.Y = this.Top;
				return p;
			}
		}

		public SIZE Size
		{
			get
			{
				var s = new SIZE();
				s.Width = this.Width;
				s.Height = this.Height;
				return s;
			}
		}

		public int X
		{
			set
			{
				this.Left = value;
			}
			get
			{
				return this.Left;
			}
		}

		public int Y
		{
			set
			{
				this.Top = value;
			}
			get
			{
				return this.Top;
			}
		}

		public int Width
		{
			get
			{
				return this.Right - this.Left;
			}
		}

		public int Height
		{
			get
			{
				return this.Bottom - this.Top;
			}
		}

		public override string ToString()
		{
			return base.ToString() + string.Format(" Left:{0} Top:{1} Right: {2} Bottom: {3} Width: {4} Height: {5}", this.Left, this.Top, this.Right, this.Bottom, this.Width, this.Height);
			//return base.ToString();
		}
	}

	#endregion

	#region MouseEventFlag

	[Flags]
	[ComVisible(true)]
	public enum MouseEventFlag : uint
	{
		Move = 0x0001,
		LeftDown = 0x0002,
		LeftUp = 0x0004,
		RightDown = 0x0008,
		RightUp = 0x0010,
		MiddleDown = 0x0020,
		MiddleUp = 0x0040,
		XDown = 0x0080,
		XUp = 0x0100,
		Wheel = 0x0800,
		VirtualDesk = 0x4000,
		Absolute = 0x8000
	}

	#endregion

	#region WIN32_FIND_DATA

	[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
	public struct WIN32_FIND_DATA
	{
		public int dwFileAttributes;
		public FILETIME_INFO ftCreationTime;
		public FILETIME_INFO ftLastAccessTime;
		public FILETIME_INFO ftLastWriteTime;
		public int nFileSizeHigh;
		public int nFileSizeLow;
		/// <summary>
		/// If the dwFileAttributes member includes the FILE_ATTRIBUTE_REPARSE_POINT attribute, this member specifies the reparse point tag. Otherwise, this value is undefined and should not be used.
		/// </summary>
		public int dwReserved0;
		/// <summary>
		/// Reserved for future use.
		/// </summary>
		public int dwReserved1;
		/// <summary>
		/// The name of the file.
		/// </summary>
		[MarshalAs(UnmanagedType.ByValTStr, SizeConst = MAX_PATH)]
		public string cFileName;
		/// <summary>
		/// An alternative name for the file.This name is in the classic 8.3 file name format.
		/// </summary>
		[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)]
		public string cAlternateFileName;

		private const int MAX_PATH = 256;//260
	}

	#endregion

	#region BY_HANDLE_FILE_INFORMATION

	public struct BY_HANDLE_FILE_INFORMATION
	{
		/// <summary>
		/// File attributes. The following table shows the possible values for dwFileAttributes.
		/// </summary>
		//[DisplayName("FileAttributes")]
		public uint dwFileAttributes;
		/// <summary>
		/// Time the file was created. If the underlying file system does not support this time member, ftCreationTime is zero.
		/// </summary>
		//[DisplayName("CreationTime")]
		public FILETIME_INFO ftCreationTime;
		/// <summary>
		/// Time the file was last accessed. If the underlying file system does not support this time member, ftLastAccessTime is zero.
		/// </summary>
		//[DisplayName("LastAccessTime")]
		public FILETIME_INFO ftLastAccessTime;
		/// <summary>
		/// Last time the file was written to.
		/// </summary>
		//[DisplayName("LastWriteTime")]
		public FILETIME_INFO ftLastWriteTime;
		/// <summary>
		/// Serial number of the volume that contains the file.
		/// </summary>
		//[DisplayName("VolumeSerialNumber")]
		public uint dwVolumeSerialNumber;
		/// <summary>
		/// High-order word of the file size.
		/// </summary>
		//[DisplayName("FileSizeHigh")]
		public uint nFileSizeHigh;
		/// <summary>
		/// Low-order word of the file size.
		/// </summary>
		//[DisplayName("FileSizeLow")]
		public uint nFileSizeLow;
		/// <summary>
		/// Number of links to this file. For the FAT file system this member is always 1.
		/// </summary>
		//[DisplayName("NumberOfLinks")]
		public uint nNumberOfLinks;
		/// <summary>
		/// High-order word of a unique identifier associated with the file.
		/// </summary>
		//[DisplayName("FileIndexHigh")]
		public uint nFileIndexHigh;
		/// <summary>
		/// Low-order word of a unique identifier associated with the file. This identifier and the volume serial number uniquely identify a file. This number may change when the system is restarted or when the file is opened. After a process opens a file, the identifier is constant until the file is closed. An application can use this identifier and the volume serial number to determine whether two handles refer to the same file.
		/// </summary>
		//[DisplayName("FileIndexLow")]
		public uint nFileIndexLow;
		/// <summary>
		/// Object identifier of the file. This parameter is only valid on files that are stored in the object store. Files on external file systems do not have object identifiers associated with them.
		/// </summary>
		//[DisplayName("OID")]
		public uint dwOID;
	}

	#endregion

	#region CPU_INFO

	/// <summary>
	/// 定义CPU的信息结构
	/// </summary>
	[ComVisible(true)]
	[StructLayout(LayoutKind.Sequential)]
	public struct CPU_INFO
	{
		public uint dwOemId;
		public uint dwPageSize;
		public uint lpMinimumApplicationAddress;
		public uint lpMaximumApplicationAddress;
		public uint dwActiveProcessorMask;
		public uint dwNumberOfProcessors;
		public uint dwProcessorType;
		public uint dwAllocationGranularity;
		public uint dwProcessorLevel;
		public uint dwProcessorRevision;
	}

	#endregion

	#region MEMORY_INFO

	/// <summary>
	/// 定义内存的信息结构
	/// </summary>
	[ComVisible(true)]
	[StructLayout(LayoutKind.Sequential)]
	public struct MEMORY_INFO
	{
		public uint dwLength;
		public uint dwMemoryLoad;
		public uint dwTotalPhys;
		public uint dwAvailPhys;
		public uint dwTotalPageFile;
		public uint dwAvailPageFile;
		public uint dwTotalVirtual;
		public uint dwAvailVirtual;
	}

	#endregion

	#region FILETIME_INFO

	[ComVisible(true)]
	[StructLayout(LayoutKind.Sequential)]
	public struct FILETIME_INFO
	{
		public uint dwLowDateTime;
		public uint dwHighDateTime;

		public SYSTEMTIME_INFO GetSYSTEMTIME()
		{
			var s = new SYSTEMTIME_INFO();
			var l = Kernel32.FileTimeToSystemTime(ref this, ref s);
			return s;
		}

		public DateTime GetDateTime()
		{
			var s = new SYSTEMTIME_INFO();
			var l = Kernel32.FileTimeToSystemTime(ref this, ref s);
			return s.GetDateTime();
		}
	}

	#endregion

	#region SYSTEMTIME_INFO

	/// <summary>
	/// 定义系统时间的信息结构
	/// </summary>
	[ComVisible(true)]
	[StructLayout(LayoutKind.Sequential)]
	public struct SYSTEMTIME_INFO
	{
		public ushort wYear;
		public ushort wMonth;
		public ushort wDayOfWeek;
		public ushort wDay;
		public ushort wHour;
		public ushort wMinute;
		public ushort wSecond;
		public ushort wMilliseconds;

		public DateTime GetDateTime()
		{
			return new DateTime(this.wYear, this.wMonth, this.wDay, this.wHour, this.wMinute, this.wSecond, this.wMilliseconds, DateTimeKind.Utc);
		}
	}

	#endregion

	#region BITMAPINFOHEADER

	/// <summary>
	/// 
	/// </summary>
	[ComVisible(true)]
	[StructLayout(LayoutKind.Sequential)]
	public struct BITMAPINFOHEADER
	{
		[MarshalAs(UnmanagedType.I4)]
		public Int32 biSize;
		[MarshalAs(UnmanagedType.I4)]
		public Int32 biWidth;
		[MarshalAs(UnmanagedType.I4)]
		public Int32 biHeight;
		[MarshalAs(UnmanagedType.I2)]
		public short biPlanes;
		[MarshalAs(UnmanagedType.I2)]
		public short biBitCount;
		[MarshalAs(UnmanagedType.I4)]
		public Int32 biCompression;
		[MarshalAs(UnmanagedType.I4)]
		public Int32 biSizeImage;
		[MarshalAs(UnmanagedType.I4)]
		public Int32 biXPelsPerMeter;
		[MarshalAs(UnmanagedType.I4)]
		public Int32 biYPelsPerMeter;
		[MarshalAs(UnmanagedType.I4)]
		public Int32 biClrUsed;
		[MarshalAs(UnmanagedType.I4)]
		public Int32 biClrImportant;
	}

	#endregion

	#region BITMAPINFO

	/// <summary>
	/// 
	/// </summary>
	[ComVisible(true)]
	[StructLayout(LayoutKind.Sequential)]
	public struct BITMAPINFO
	{
		[MarshalAs(UnmanagedType.Struct, SizeConst = 40)]
		public BITMAPINFOHEADER bmiHeader;
		[MarshalAs(UnmanagedType.ByValArray, SizeConst = 1024)]
		public int[] bmiColors;
	}

	#endregion

	#region SHFILEINFO

	[StructLayout(LayoutKind.Sequential)]
	public struct SHFILEINFO
	{
		public IntPtr hIcon;
		public IntPtr iIcon;
		public uint dwAttributes;
		[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
		public string szDisplayName;
		[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 80)]
		public string szTypeName;
	}

	#endregion

	#region VIDEOHDR

	/// <summary>
	/// 
	/// </summary>
	[ComVisible(true)]
	[StructLayout(LayoutKind.Sequential)]
	public struct VIDEOHDR
	{
		[MarshalAs(UnmanagedType.I4)]
		public int lpData;
		[MarshalAs(UnmanagedType.I4)]
		public int dwBufferLength;
		[MarshalAs(UnmanagedType.I4)]
		public int dwBytesUsed;
		[MarshalAs(UnmanagedType.I4)]
		public int dwTimeCaptured;
		[MarshalAs(UnmanagedType.I4)]
		public int dwUser;
		[MarshalAs(UnmanagedType.I4)]
		public int dwFlags;
		[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
		public int[] dwReserved;
	}

	#endregion

	#region KeyModifiers

	/// <summary>
	/// 组合键枚举
	/// </summary>
	[Flags]
	[ComVisible(true)]
	public enum KeyModifiers
	{
		None = 0,
		Alt = 1,
		Control = 2,
		Shift = 4,
		Windows = 8
	}

	#endregion

	#region PropSpec

	/// <summary>
	/// PropSpec [IPropertySetStorage] 
	/// </summary>
	[ComVisible(true)]
	[StructLayout(LayoutKind.Explicit, Size = 8, CharSet = CharSet.Unicode)]
	public struct PropSpec
	{
		/// <summary>
		/// PRSPEC_LPWSTR:0;PRSPEC_PROPID:1;
		/// </summary>
		[FieldOffset(0)]
		public int ulKind;
		[FieldOffset(4)]
		public IntPtr Name_Or_ID;
	}

	#endregion

	#region PropVariant

	/// <summary>
	/// PropVariant [IPropertySetStorage] 
	/// </summary>
	[ComVisible(true)]
	[StructLayout(LayoutKind.Explicit, Size = 16)]
	public struct PropVariant
	{
		[FieldOffset(0)]
		public short variantType;
		[FieldOffset(8)]
		public IntPtr pointerValue;
		[FieldOffset(8)]
		public byte byteValue;
		[FieldOffset(8)]
		public long longValue;

		public void FromObject(object obj)
		{
			if (obj.GetType() == typeof(string))
			{
				this.variantType = (short)VarEnum.VT_LPWSTR;
				this.pointerValue = Marshal.StringToHGlobalUni((string)obj);
			}
		}

		public object ToObject()
		{
			switch ((VarEnum)this.variantType)
			{
				case VarEnum.VT_BSTR:
					return Marshal.PtrToStringBSTR(this.pointerValue);
					//Marshal.FreeCoTaskMem(this.pointerValue);
				case VarEnum.VT_UI1:
					return this.byteValue;
				case VarEnum.VT_UI2:
					return (short)this.longValue;
				case VarEnum.VT_I4:
					return (int)this.pointerValue;
				case VarEnum.VT_UI8:
					return this.longValue;
				case VarEnum.VT_INT:
					return (short)this.longValue;
				case VarEnum.VT_LPSTR:
					return Marshal.PtrToStringAnsi(this.pointerValue);
					//Marshal.FreeCoTaskMem(this.pointerValue);
				case VarEnum.VT_LPWSTR:
					return Marshal.PtrToStringUni(this.pointerValue);
					//Marshal.FreeCoTaskMem(ptr);
				case VarEnum.VT_FILETIME:
					return DateTime.FromFileTime(this.longValue);
				case VarEnum.VT_BOOL:
					return (this.byteValue == 0 ? false : true);
				case VarEnum.VT_NULL:
				case VarEnum.VT_EMPTY:
					return null;
				default:
					throw new ArgumentException(String.Format("Unsupported variant type {0}", this.variantType));
			}
			return null;
		}
	}

	#endregion

	#region STATPROPSTG

	[ComVisible(true)]
	[StructLayout(LayoutKind.Sequential)]
	public struct STATPROPSTG
	{
		public IntPtr lpwstrName;
		public int propid;
		public short vt;
	}

	#endregion

	#region IPropertySetStorage

	/// <summary>
	/// IPropertySetStorage [StgCreateStorageEx | StgOpenStorageEx]
	/// </summary>
	[ComImport]
	[ComVisible(true)]
	[Guid(FileSummary.IID_PropertySetStorage)]
	[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
	public interface IPropertySetStorage
	{
		/// <summary>
		/// Creates a new property set.
		/// </summary>
		/// <param name="rfmtid"></param>
		/// <param name="pclsid"></param>
		/// <param name="grfFlags"></param>
		/// <param name="grfMode"></param>
		/// <param name="propertyStorage"></param>
		/// <returns></returns>
		uint Create([In, MarshalAs(UnmanagedType.Struct)] ref Guid rfmtid, [In] IntPtr pclsid, [In] int grfFlags, [In] int grfMode, ref IPropertyStorage propertyStorage);

		/// <summary>
		/// Opens a previously created property set.
		/// </summary>
		/// <param name="rfmtid"></param>
		/// <param name="grfMode"></param>
		/// <param name="propertyStorage"></param>
		/// <returns></returns>
		uint Open([In, MarshalAs(UnmanagedType.Struct)] ref Guid rfmtid, [In] int grfMode, [Out] out IPropertyStorage propertyStorage);

		/// <summary>
		/// Deletes an existing property set.
		/// </summary>
		/// <param name="rfmtid"></param>
		/// <returns></returns>
		uint Delete([In, MarshalAs(UnmanagedType.Struct)] ref Guid rfmtid);
	}

	#endregion

	#region IPropertyStorage

	/// <summary>
	/// IPropertyStorage [IPropertySetStorage]
	/// </summary>
	[ComImport]
	[ComVisible(true)]
	[Guid(FileSummary.IID_PropertyStorage)]
	[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
	public interface IPropertyStorage
	{
		/// <summary>
		/// 
		/// </summary>
		/// <param name="numProperties"></param>
		/// <param name="propertySpecifications"></param>
		/// <param name="propertyValues"></param>
		/// <returns></returns>
		/// <!-- LPArray、ByValArray 或 SafeArray -->
		uint ReadMultiple([In] uint numProperties,
			[In, Out, MarshalAs(UnmanagedType.Struct)] ref PropSpec propertySpecifications,
			[In, Out, MarshalAs(UnmanagedType.Struct)] ref PropVariant propertyValues);
		//uint ReadMultiple([In] uint numProperties,
		//    [In, MarshalAs(UnmanagedType.SafeArray, SafeArrayUserDefinedSubType=typeof(PropSpec))] PropSpec[] propertySpecifications,
		//    [Out, MarshalAs(UnmanagedType.SafeArray, SafeArrayUserDefinedSubType = typeof(PropVariant))] PropVariant[] propertyValues);

		/// <summary>
		/// 
		/// </summary>
		/// <param name="numProperties"></param>
		/// <param name="propertySpecification"></param>
		/// <param name="propertyValues"></param>
		/// <param name="propIDNameFirst"></param>
		/// <returns></returns>
		uint WriteMultiple([In] uint numProperties, [MarshalAs(UnmanagedType.Struct)] ref PropSpec propertySpecification, ref PropVariant propertyValues, int propIDNameFirst);

		/// <summary>
		/// 
		/// </summary>
		/// <param name="cpropid">The size on input of the array rgpropid. Can be zero. However, making it zero causes this method to become non-operational.</param>
		/// <param name="rgpropid">An array of the property IDs for which names are to be set.</param>
		/// <param name="rglpwstrName">An array of new names to be assigned to the corresponding property IDs in the rgpropid array. These names may not exceed 255 characters (not including the NULL terminator).</param>
		/// <returns></returns>
		uint WritePropertyNames([In] uint cpropid, [In] uint[] rgpropid, [In]  string[] rglpwstrName);

		/// <summary>
		/// 
		/// </summary>
		/// <param name="ppEnum"></param>
		//void Enum([Out, MarshalAs(UnmanagedType.Interface)] out IEnumSTATPROPSTG ppEnum);
		void Enum([In, Out]ref IEnumSTATPROPSTG ppEnum);

		/// <summary/>
		uint Commit(int commitFlags);
	}

	#endregion

	#region IEnumSTATPROPSTG

	[ComImport]
	[ComVisible(true)]
	[Guid(FileSummary.IID_EnumSTATPROPSTG)]
	[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
	public interface IEnumSTATPROPSTG
	{
		void Clone([Out] out IEnumSTATPROPSTG ppEnum);
		[PreserveSig]
		int Next([In] uint celt, [Out] out STATPROPSTG[] rgelt, [Out] out uint pceltFetched);
		int Reset();
		int Skip([In] uint celt);
	}

	#endregion

	#region OFSTRUCT

	/// <summary>
	/// 
	/// </summary>
	[StructLayout(LayoutKind.Sequential)]
	public struct OFSTRUCT
	{
		/// <summary>
		/// The size of the structure, in bytes.
		/// </summary>
		public byte cBytes;
		/// <summary>
		/// If this member is nonzero, the file is on a hard (fixed) disk. Otherwise, it is not.
		/// </summary>
		public byte fFixedDisk;
		/// <summary>
		/// The MS-DOS error code if the OpenFile function failed.
		/// </summary>
		public int nErrCode;
		/// <summary>
		/// Reserved; do not use.
		/// </summary>
		public int Reserved1;
		/// <summary>
		/// Reserved; do not use.
		/// </summary>
		public int Reserved2;
		/// <summary>
		/// The path and file name of the file.
		/// </summary>
		[MarshalAs(UnmanagedType.ByValTStr, SizeConst = byte.MaxValue)]
		public string szPathName;
	}

	/// <summary>
	/// 
	/// </summary>
	public enum OF : int
	{
		/// <summary>
		/// Ignored.
		/// To produce a dialog box containing a Cancel button, use OF_PROMPT.
		/// </summary>
		Cancel = 0x00000800,
		/// <summary>
		/// Creates a new file.
		/// If the file exists, it is truncated to zero (0) length.
		/// </summary>
		Create = 0x00001000,
		/// <summary>
		/// Deletes a file.
		/// </summary>
		Delete = 0x00000200,
		/// <summary>
		/// Opens a file and then closes it.
		/// Use this to test for the existence of a file.
		/// </summary>
		Exist = 0x00004000,
		/// <summary>
		/// Fills the OFSTRUCT structure, but does not do anything else.
		/// </summary>
		Parse = 0x00000100,
		/// <summary>
		/// Displays a dialog box if a requested file does not exist.
		/// A dialog box informs a user that the system cannot find a file, and it contains Retry and Cancel buttons. The Cancel button directs OpenFile to return a file-not-found error message.
		/// </summary>
		Prompt = 0x00002000,
		/// <summary>
		/// Opens a file for reading only.
		/// </summary>
		Read = 0x00000000,
		/// <summary>
		/// Opens a file with read/write permissions.
		/// </summary>
		ReadWrite = 0x00000002,
		/// <summary>
		/// Opens a file by using information in the reopen buffer.
		/// </summary>
		Reopen = 0x00008000,
		/// <summary>
		/// For MS-DOS–based file systems, opens a file with compatibility mode, allows any process on a specified computer to open the file any number of times.
		/// Other efforts to open a file with other sharing modes fail. This flag is mapped to the FILE_SHARE_READ|FILE_SHARE_WRITE flags of the CreateFile function.
		/// </summary>
		ShareCompat = 0x00000000,
		/// <summary>
		/// Opens a file without denying read or write access to other processes.
		/// On MS-DOS-based file systems, if the file has been opened in compatibility mode by any other process, the function fails.
		/// This flag is mapped to the FILE_SHARE_READ|FILE_SHARE_WRITE flags of the CreateFile function.
		/// </summary>
		ShareDenyNone = 0x00000040,
		/// <summary>
		/// Opens a file and denies read access to other processes.
		/// On MS-DOS-based file systems, if the file has been opened in compatibility mode, or for read access by any other process, the function fails.
		/// This flag is mapped to the FILE_SHARE_WRITE flag of the CreateFile function.
		/// </summary>
		ShareDenyRead = 0x00000030,
		/// <summary>
		/// Opens a file and denies write access to other processes.
		/// On MS-DOS-based file systems, if a file has been opened in compatibility mode, or for write access by any other process, the function fails.
		/// This flag is mapped to the FILE_SHARE_READ flag of the CreateFile function.
		/// </summary>
		ShareDenyWrite = 0x00000020,
		/// <summary>
		/// Opens a file with exclusive mode, and denies both read/write access to other processes. If a file has been opened in any other mode for read/write access, even by the current process, the function fails.
		/// </summary>
		ShareExclusive = 0x00000010,
		/// <summary>
		/// Verifies that the date and time of a file are the same as when it was opened previously.
		/// This is useful as an extra check for read-only files.
		/// </summary>
		Verify = -1,
		/// <summary>
		/// Opens a file for write access only.
		/// </summary>
		Write = 0x00000001,
	}

	#endregion

	#region ReparseTagType

	/// <summary>
	/// 
	/// </summary>
	public enum ReparseTagType : uint
	{
		/// <summary>
		/// IO_REPARSE_TAG_MOUNT_POINT
		/// </summary>
		MountPoint = IO_REPARSE_TAG.MOUNT_POINT,		// Moiunt point or junction, see winnt.h
		/// <summary>
		/// IO_REPARSE_TAG_HSM
		/// </summary>
		HSM = IO_REPARSE_TAG.HSM,
		/// <summary>
		/// IO_REPARSE_TAG_SIS
		/// </summary>
		SIS = IO_REPARSE_TAG.SIS,
		/// <summary>
		/// IO_REPARSE_TAG_DFS
		/// </summary>
		DFS = IO_REPARSE_TAG.DFS,
		/// <summary>
		/// IO_REPARSE_TAG_SYMLINK
		/// </summary>
		Symlink = IO_REPARSE_TAG.SYMLINK,			// SYMLINK or SYMLINKD (see http://wesnerm.blogs.com/net_undocumented/2006/10/index.html)
		/// <summary>
		/// IO_REPARSE_TAG_DFSR
		/// </summary>
		DFSR = IO_REPARSE_TAG.DFSR,
	}

	#endregion

	#region REPARSE_DATA_BUFFER

	// This is the official version of the data buffer, see http://msdn2.microsoft.com/en-us/library/ms791514.aspx
	// not the one used at http://www.flexhex.com/docs/articles/hard-links.phtml
	/// <summary>
	/// 
	/// </summary>
	[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
	public struct REPARSE_DATA_BUFFER// max length = 16KB.
	{
		public const string PATH_PREFIX = @"\??\";
		/// <summary>
		/// 
		/// </summary>
		public const int MAXIMUM_REPARSE_DATA_BUFFER_SIZE = 16 * 1024;

		public REPARSE_DATA_BUFFER(ReparseTagType reparseTag)
		{
			this.ReparseTag = reparseTag;
			this.ReparseDataLength = (ushort)Marshal.SizeOf(typeof(REPARSE_DATA_BUFFER));// MAXIMUM_REPARSE_DATA_BUFFER_SIZE;
			this.Reserved = 0;
			this.SubstituteNameOffset = 0;
			this.SubstituteNameLength = 0;
			this.PrintNameOffset = 0;
			this.PrintNameLength = 0;
			this.DataBuffer = new byte[MAXIMUM_REPARSE_DATA_BUFFER_SIZE - 16];
		}

		public REPARSE_DATA_BUFFER(IntPtr p) : this(ReparseTagType.MountPoint)
		{
			if (p == IntPtr.Zero)
				return;

			this.SetPrt(p);
		}

		public IntPtr GetPtr()
		{
			var size = Marshal.SizeOf(this);
			var buffer = Marshal.AllocHGlobal(size);
			Marshal.StructureToPtr(this, buffer, false);
			return buffer;
		}

		public void SetPrt(IntPtr p)
		{
			this.DataBuffer = new byte[MAXIMUM_REPARSE_DATA_BUFFER_SIZE - 16];
			if (p == IntPtr.Zero)
				return;

			try
			{
				Marshal.PtrToStructure(p, this);
				return;
			}
			catch// (Exception x)
			{
				//
			}

			var @this = (REPARSE_DATA_BUFFER)Marshal.PtrToStructure(p, this.GetType());
			this.ReparseTag = @this.ReparseTag;
			this.ReparseDataLength = @this.ReparseDataLength;
			this.Reserved = @this.Reserved;
			this.SubstituteNameOffset = @this.SubstituteNameOffset;
			this.SubstituteNameLength = @this.SubstituteNameLength;
			this.PrintNameOffset = @this.PrintNameOffset;
			this.PrintNameLength = @this.PrintNameLength;
			this.DataBuffer = @this.DataBuffer;
		}

		public string SubstituteName
		{
			set
			{
				var bs = Encoding.Unicode.GetBytes(PATH_PREFIX + Path.GetFullPath(value));
				if (this.DataBuffer != null && this.DataBuffer.Length > bs.Length)
				{
					this.SubstituteNameOffset = 0;
					this.SubstituteNameLength = (ushort)bs.Length;
					var ds = new byte[this.PrintNameLength];
					if (this.PrintNameLength > 0)
						Array.Copy(this.DataBuffer, this.PrintNameOffset, ds, 0, this.PrintNameLength);
					this.PrintNameOffset = (ushort)(this.SubstituteNameLength + 2);
					Array.Copy(bs, 0, this.DataBuffer, this.SubstituteNameOffset, this.SubstituteNameLength);
					if (this.PrintNameLength > 0)
						Array.Copy(ds, 0, this.DataBuffer, this.PrintNameOffset, this.PrintNameLength);
					this.ReparseDataLength = (ushort)Marshal.SizeOf(this);
					return;
				}

				this.DataBuffer = bs;
				this.ReparseDataLength = (ushort)Marshal.SizeOf(this);
			}
			get
			{
				if (this.SubstituteNameLength > 0)
				{
					if (this.ReparseTag == ReparseTagType.Symlink)
						return Encoding.Unicode.GetString(this.DataBuffer, this.SubstituteNameOffset + Encoding.Unicode.GetByteCount("\0\0"), this.SubstituteNameLength);

					return Encoding.Unicode.GetString(this.DataBuffer, this.SubstituteNameOffset, this.SubstituteNameLength);
				}

				return string.Empty;
			}
		}

		public string PrintName
		{
			set
			{
				var bs = Encoding.Unicode.GetBytes(PATH_PREFIX + Path.GetFullPath(value));
				if (this.SubstituteNameOffset > 0 && this.SubstituteNameLength > 0)
					this.PrintNameOffset = (ushort)(this.SubstituteNameOffset + this.SubstituteNameLength + 2);
				else
					this.PrintNameOffset = 0;
				this.PrintNameLength = (ushort)bs.Length;
				if (this.DataBuffer != null && this.DataBuffer.Length > bs.Length)
				{
					if (this.DataBuffer.Length >= this.PrintNameOffset + this.PrintNameLength)
					{
						Array.Copy(bs, 0, this.DataBuffer, this.PrintNameOffset, this.PrintNameLength);
						this.ReparseDataLength = (ushort)Marshal.SizeOf(this);
						return;
					}

					var ds = new byte[this.PrintNameOffset + this.PrintNameLength];
					if (this.SubstituteNameOffset + this.SubstituteNameLength > 0)
						Array.Copy(this.DataBuffer, 0, ds, 0, this.DataBuffer.Length);
					Array.Copy(bs, 0, ds, this.PrintNameOffset, this.PrintNameLength);
					this.DataBuffer = ds;
					this.ReparseDataLength = (ushort)Marshal.SizeOf(this);
					return;
				}

				this.DataBuffer = bs;
				this.ReparseDataLength = (ushort)Marshal.SizeOf(this);
			}
			get
			{
				if (this.PrintNameLength > 0)
				{
					if (this.ReparseTag == ReparseTagType.Symlink)
						return Encoding.Unicode.GetString(this.DataBuffer, this.PrintNameOffset + Encoding.Unicode.GetByteCount("\0\0"), this.PrintNameLength);

					return Encoding.Unicode.GetString(this.DataBuffer, this.PrintNameOffset, this.PrintNameLength);
				}

				return string.Empty;
			}
		}

		/// <summary>
		/// Reparse point tag. Must be a Microsoft reparse point tag.
		/// </summary>
		[MarshalAs(UnmanagedType.U4)]
		public ReparseTagType ReparseTag;
		/// <summary>
		/// Size, in bytes, of the data after the Reserved member. This can be calculated by:
		/// (4 * sizeof(ushort)) + SubstituteNameLength + PrintNameLength + (namesAreNullTerminated ? 2 * sizeof(char) : 0);
		/// </summary>
		[MarshalAs(UnmanagedType.U2)]
		public ushort ReparseDataLength;
		/// <summary>
		/// Reserved; do not use.
		/// </summary>
		[MarshalAs(UnmanagedType.U2)]
		public ushort Reserved;
		/// <summary>
		/// Offset, in bytes, of the substitute name string in the PathBuffer array.
		/// </summary>
		[MarshalAs(UnmanagedType.U2)]
		public ushort SubstituteNameOffset;
		/// <summary>
		/// Length, in bytes, of the substitute name string. If this string is null-terminated,SubstituteNameLength does not include space for the null character.
		/// </summary>
		[MarshalAs(UnmanagedType.U2)]
		public ushort SubstituteNameLength;
		/// <summary>
		/// Offset, in bytes, of the print name string in the PathBuffer array.
		/// </summary>
		[MarshalAs(UnmanagedType.U2)]
		public ushort PrintNameOffset;
		/// <summary>
		/// Length, in bytes, of the print name string. If this string is null-terminated,PrintNameLength does not include space for the null character.
		/// </summary>
		[MarshalAs(UnmanagedType.U2)]
		public ushort PrintNameLength;
		/// <summary>
		/// A buffer containing the unicode-encoded path string. The path string contains the substitute name string and print name string.
		/// </summary>
		[MarshalAs(UnmanagedType.ByValArray, SizeConst = MAXIMUM_REPARSE_DATA_BUFFER_SIZE - 16)]
		public byte[] DataBuffer;

		/// <summary>
		/// 
		/// </summary>
		/// <param name="hDevice"></param>
		/// <param name="dwIoControlCode"></param>
		/// <param name="pBytesReturned"></param>
		/// <param name="lpOverlapped"></param>
		/// <returns></returns>
		public bool DeviceIoControl(IntPtr hDevice, uint dwIoControlCode, out int pBytesReturned)
		{
			var s = (ushort)Marshal.SizeOf(this);
			var h = Marshal.AllocHGlobal(s);
			if (this.PrintNameLength > 0)
				this.ReparseDataLength = (ushort)(this.PrintNameLength + this.PrintNameOffset + 12);
			else if (this.SubstituteNameLength > 0)
				this.ReparseDataLength = (ushort)(this.SubstituteNameLength + this.SubstituteNameOffset + 12);
			else
				this.ReparseDataLength = 0;
			var b = true;
			Marshal.StructureToPtr(this, h, b);
			dwIoControlCode = FSCTL.GetCode(dwIoControlCode);
			if (dwIoControlCode == FSCTL.GetReparsePoint)
				b = Kernel32.DeviceIoControl(hDevice, dwIoControlCode, IntPtr.Zero, 0, h, s, out pBytesReturned, IntPtr.Zero);
			else
				b = Kernel32.DeviceIoControl(hDevice, dwIoControlCode, h, this.ReparseDataLength + 8, IntPtr.Zero, 0, out pBytesReturned, IntPtr.Zero);
			if (b && pBytesReturned > 0)
				this.SetPrt(h);
			Marshal.FreeHGlobal(h);
			return b;
		}
	}

	#endregion

	#region public enum RESOURCE_SCOPE

	public enum RESOURCE_SCOPE
	{
		CONNECTED = 1,
		GLOBALNET = 2,
		REMEMBERED = 3,
		RECENT = 4,
		CONTEXT = 5
	}

	#endregion

	#region public enum RESOURCE_TYPE

	public enum RESOURCE_TYPE
	{
		ANY = 0,
		DISK = 1,
		PRINT = 2,
		RESERVED = 8,
	}

	#endregion

	#region public enum RESOURCE_USAGE

	/// <summary/>
	[Flags]
	public enum RESOURCE_USAGE
	{
		/// <summary/>
		CONNECTABLE = 1,
		/// <summary/>
		CONTAINER = 2,
		/// <summary/>
		NOLOCALDEVICE = 4,
		/// <summary/>
		SIBLING = 8,
		/// <summary/>
		ATTACHED = 16,
		/// <summary/>
		ALL = (CONNECTABLE | CONTAINER | ATTACHED),
	}

	#endregion

	#region public enum RESOURCE_DISPLAYTYPE

	/// <summary/>
	public enum RESOURCE_DISPLAY_TYPE
	{
		/// <summary/>
		GENERIC = 0,
		/// <summary/>
		DOMAIN = 1,
		/// <summary/>
		SERVER = 2,
		/// <summary/>
		SHARE = 3,
		/// <summary/>
		FILE = 4,
		/// <summary/>
		GROUP = 5,
		/// <summary/>
		NETWORK = 6,
		/// <summary/>
		ROOT = 7,
		/// <summary/>
		SHAREADMIN = 8,
		/// <summary/>
		DIRECTORY = 9,
		/// <summary/>
		TREE = 10,
		/// <summary/>
		NDSCONTAINER = 11
	}

	#endregion

	#region NET_RESOURCE

	/// <summary/>
	[StructLayout(LayoutKind.Sequential)]
	public struct NET_RESOURCE
	{
		/// <summary/>
		public RESOURCE_SCOPE dwScope;
		/// <summary/>
		public RESOURCE_TYPE dwType;
		/// <summary/>
		public RESOURCE_DISPLAY_TYPE dwDisplayType;
		/// <summary/>
		public RESOURCE_USAGE dwUsage;
		/// <summary/>
		[MarshalAs(UnmanagedType.LPStr)]
		public string lpLocalName;
		/// <summary/>
		[MarshalAs(UnmanagedType.LPStr)]
		public string lpRemoteName;
		/// <summary/>
		[MarshalAs(UnmanagedType.LPStr)]
		public string lpComment;
		/// <summary/>
		[MarshalAs(UnmanagedType.LPStr)]
		public string lpProvider;
	}

	#endregion

	#region WinSpool any

	/// <summary/>
	[FlagsAttribute]
	public enum PRINTER_ENUM
	{
		/// <summary/>
		PRINTER_ENUM_DEFAULT = 0x00000001,
		/// <summary/>
		PRINTER_ENUM_LOCAL = 0x00000002,
		/// <summary/>
		PRINTER_ENUM_CONNECTIONS = 0x00000004,
		/// <summary/>
		PRINTER_ENUM_FAVORITE = 0x00000004,
		/// <summary/>
		PRINTER_ENUM_NAME = 0x00000008,
		/// <summary/>
		PRINTER_ENUM_REMOTE = 0x00000010,
		/// <summary/>
		PRINTER_ENUM_SHARED = 0x00000020,
		/// <summary/>
		PRINTER_ENUM_NETWORK = 0x00000040,
		/// <summary/>
		PRINTER_ENUM_EXPAND = 0x00004000,
		/// <summary/>
		PRINTER_ENUM_CONTAINER = 0x00008000,
		/// <summary/>
		PRINTER_ENUM_ICONMASK = 0x00ff0000,
		/// <summary/>
		PRINTER_ENUM_ICON1 = 0x00010000,
		/// <summary/>
		PRINTER_ENUM_ICON2 = 0x00020000,
		/// <summary/>
		PRINTER_ENUM_ICON3 = 0x00040000,
		/// <summary/>
		PRINTER_ENUM_ICON4 = 0x00080000,
		/// <summary/>
		PRINTER_ENUM_ICON5 = 0x00100000,
		/// <summary/>
		PRINTER_ENUM_ICON6 = 0x00200000,
		/// <summary/>
		PRINTER_ENUM_ICON7 = 0x00400000,
		/// <summary/>
		PRINTER_ENUM_ICON8 = 0x00800000,
		/// <summary/>
		PRINTER_ENUM_HIDE = 0x01000000,
	}

	[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
	public struct PRINTER_INFO_1
	{
		public int flags;
		public string pDescription;
		public string pName;
		public string pComment;
	}

	/// <summary/>
	[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
	public struct PRINTER_INFO_2
	{
		/// <summary/>
		[MarshalAs(UnmanagedType.LPTStr)]
		public string pServerName;
		/// <summary/>
		[MarshalAs(UnmanagedType.LPTStr)]
		public string pPrinterName;
		/// <summary/>
		[MarshalAs(UnmanagedType.LPTStr)]
		public string pShareName;
		/// <summary/>
		[MarshalAs(UnmanagedType.LPTStr)]
		public string pPortName;
		/// <summary/>
		[MarshalAs(UnmanagedType.LPTStr)]
		public string pDriverName;
		/// <summary/>
		[MarshalAs(UnmanagedType.LPTStr)]
		public string pComment;
		/// <summary/>
		[MarshalAs(UnmanagedType.LPTStr)]
		public string pLocation;
		/// <summary/>
		public IntPtr pDevMode;
		/// <summary/>
		[MarshalAs(UnmanagedType.LPTStr)]
		public string pSepFile;
		/// <summary/>
		[MarshalAs(UnmanagedType.LPTStr)]
		public string pPrintProcessor;
		/// <summary/>
		[MarshalAs(UnmanagedType.LPTStr)]
		public string pDatatype;
		/// <summary/>
		[MarshalAs(UnmanagedType.LPTStr)]
		public string pParameters;
		/// <summary/>
		public IntPtr pSecurityDescriptor;
		/// <summary/>
		public uint Attributes;
		/// <summary/>
		public uint Priority;
		/// <summary/>
		public uint DefaultPriority;
		/// <summary/>
		public uint StartTime;
		/// <summary/>
		public uint UntilTime;
		/// <summary/>
		public uint Status;
		/// <summary/>
		public uint cJobs;
		/// <summary/>
		public uint AveragePPM;

	}

	/// <summary/>
	public enum DMDO
	{
		/// <summary/>
		DEFAULT = 0,
		/// <summary/>
		D90 = 1,
		/// <summary/>
		D180 = 2,
		/// <summary/>
		D270 = 3,
	}

	/// <summary/>
	[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
	public struct DEVMODE
	{
		/// <summary/>
		public const int DM_DISPLAYFREQUENCY = 0x400000;
		/// <summary/>
		public const int DM_PELSWIDTH = 0x80000;
		/// <summary/>
		public const int DM_PELSHEIGHT = 0x100000;
		/// <summary/>
		private const int CCHDEVICENAME = 32;
		/// <summary/>
		private const int CCHFORMNAME = 32;
		/// <summary/>
		[MarshalAs(UnmanagedType.ByValTStr, SizeConst = CCHDEVICENAME)]
		public string dmDeviceName;
		/// <summary/>
		public short dmSpecVersion;
		/// <summary/>
		public short dmDriverVersion;
		/// <summary/>
		public short dmSize;
		/// <summary/>
		public short dmDriverExtra;
		/// <summary/>
		public int dmFields;
		/// <summary/>
		public short dmOrientation;
		/// <summary/>
		public short dmPaperSize;
		/// <summary/>
		public short dmPaperLength;
		/// <summary/>
		public short dmPaperWidth;
		/// <summary/>
		public short dmScale;
		/// <summary/>
		public short dmCopies;
		/// <summary/>
		public short dmDefaultSource;
		/// <summary/>
		public short dmPrintQuality;
		/// <summary/>
		public short dmColor;
		/// <summary/>
		public short dmDuplex;
		/// <summary/>
		public short dmYResolution;
		/// <summary/>
		public short dmTTOption;
		/// <summary/>
		public short dmCollate;
		/// <summary/>
		[MarshalAs(UnmanagedType.ByValTStr, SizeConst = CCHFORMNAME)]
		public string dmFormName;
		/// <summary/>
		public short dmLogPixels;
		/// <summary/>
		public int dmBitsPerPel;
		/// <summary/>
		public int dmPelsWidth;
		/// <summary/>
		public int dmPelsHeight;
		/// <summary/>
		public int dmDisplayFlags;
		/// <summary/>
		public int dmDisplayFrequency;
	}

	/// <summary/>
	[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
	public struct PRINTER_DEFAULTS
	{
		//public const int DM_DUPLEX = 0x1000;
		//public const int DM_IN_BUFFER = 8;
		//public const int DM_OUT_BUFFER = 2;
		/// <summary/>
		public const int PRINTER_ACCESS_ADMINISTER = 0x4;
		/// <summary/>
		public const int PRINTER_ACCESS_USE = 0x8;
		/// <summary/>
		public const int STANDARD_RIGHTS_REQUIRED = 0xF0000;
		/// <summary/>
		public const int PRINTER_EXECUTE = 0x00020008;
		/// <summary/>
		public const int PRINTER_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED | PRINTER_ACCESS_ADMINISTER | PRINTER_ACCESS_USE);
		/// <summary/>
		public const int SERVER_ACCESS_ADMINISTER = 0x00000001;
		/// <summary/>
		public const int SERVER_ACCESS_ENUMERATE = 0x00000002;
		/// <summary/>
		public const int SERVER_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED | SERVER_ACCESS_ADMINISTER | SERVER_ACCESS_ENUMERATE);

		/// <summary/>
		public int pDatatype;//public string pDatatype;
		/// <summary/>
		public int pDevMode;//public DEVMODE pDevMode;
		/// <summary/>
		public int DesiredAccess;
	}

	/// <summary/>
	[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
	public class DOCINFOA
	{
		/// <summary/>
		[MarshalAs(UnmanagedType.LPStr)]
		public string pDocName;
		/// <summary/>
		[MarshalAs(UnmanagedType.LPStr)]
		public string pOutputFile;
		/// <summary/>
		[MarshalAs(UnmanagedType.LPStr)]
		public string pDataType;
	}

	#endregion

	#region DCB

	/// <summary/>
	[StructLayout(LayoutKind.Sequential)]
	public struct DCB
	{
		/// <summary/>
		public int DCBlength;
		/// <summary/>
		public int BaudRate;
		/// <summary/>
		public int fBitFields;
		/// <summary/>
		public short wReserved;
		/// <summary/>
		public short XonLim;
		/// <summary/>
		public short XoffLim;
		/// <summary/>
		public byte ByteSize;
		/// <summary/>
		public byte Parity;
		/// <summary/>
		public byte StopBits;
		/// <summary/>
		public byte XonChar;
		/// <summary/>
		public byte XoffChar;
		/// <summary/>
		public byte ErrorChar;
		/// <summary/>
		public byte EofChar;
		/// <summary/>
		public byte EvtChar;
		/// <summary/>
		public short wReserved1;//Reserved; Do Not Use
	}

	#endregion

	#region COMMTIMEOUTS

	/// <summary/>
	[StructLayout(LayoutKind.Sequential)]
	public struct COMMTIMEOUTS
	{
		/// <summary/>
		public int ReadIntervalTimeout;
		/// <summary/>
		public int ReadTotalTimeoutMultiplier;
		/// <summary/>
		public int ReadTotalTimeoutConstant;
		/// <summary/>
		public int WriteTotalTimeoutMultiplier;
		/// <summary/>
		public int WriteTotalTimeoutConstant;
	}

	#endregion

	#region OVERLAPPED

	/// <summary/>
	[StructLayout(LayoutKind.Sequential)]
	public struct OVERLAPPED
	{
		/// <summary/>
		public int Internal;
		/// <summary/>
		public int InternalHigh;
		/// <summary/>
		public int Offset;
		/// <summary/>
		public int OffSetHigh;
		/// <summary/>
		public IntPtr hEvent;
	}

	#endregion

	/// <summary/>
	public delegate bool EnumWinProc(IntPtr hwnd, IntPtr lParam);
}
